package com.geline.sqlbackup.util;

import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import lombok.extern.slf4j.Slf4j;

import javax.sql.DataSource;
import java.nio.charset.Charset;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
import java.util.Map;

/**
 * jdbc解析工具
 * @author: mengx
 * @date: 2021/8/15 15:35
 */
@Slf4j
public class JdbcParseUtils {

    public static String findIpPortByUrl(String jdbcUrl) {
        // jdbc:mysql://101.133.193.94:3306/cloud-coder-sdk?useUnicode=true
        int first = jdbcUrl.indexOf("//");
        if(first == -1){
            throw new RuntimeException("error jdbcUrl format : no find // !");
        }
        String ipPortStr = jdbcUrl.substring(first+2);
        ipPortStr = ipPortStr.substring(0, ipPortStr.indexOf("/"));
        return ipPortStr;
    }

    /**
     * 解析DataSource中数据库名
     * @param dataSource
     * @return
     */
    public static String findCatalog(DataSource dataSource) {
        Connection connection = null;
        try {
            connection = dataSource.getConnection();
            DatabaseMetaData metaData = connection.getMetaData();
            String url = metaData.getURL();
            return findCatalogByUrl(url);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }finally {
            try {
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 解析url中数据库名
     * @param jdbcUrl
     * @return
     */
    public static String findCatalogByUrl(String jdbcUrl) {
        String catalog = null;
        int pos, pos1;
        String connUri;
        if (StrUtil.isBlank(jdbcUrl)) {
            throw new IllegalArgumentException("jdbcUrl can not be blank.");
        }
        jdbcUrl = jdbcUrl.toLowerCase();
        if (jdbcUrl.startsWith("jdbc:impala")) {
            jdbcUrl = jdbcUrl.replace(":impala", "");
        }
        if (!jdbcUrl.startsWith("jdbc:")
                || (pos1 = jdbcUrl.indexOf(':', 5)) == -1) {
            throw new IllegalArgumentException("Invalid JDBC url.");
        }
        connUri = jdbcUrl.substring(pos1 + 1);
        if (connUri.startsWith("//")) {
            if ((pos = connUri.indexOf('/', 2)) != -1) {
                catalog = connUri.substring(pos + 1);
            }
        } else {
            catalog = connUri;
        }
        if (catalog.contains("?")) {
            catalog = catalog.substring(0, catalog.indexOf("?"));
        }
        if (catalog.contains(";")) {
            catalog = catalog.substring(0, catalog.indexOf(";"));
        }
        if (StrUtil.isBlank(catalog)) {
            throw new IllegalArgumentException("Invalid JDBC url.");
        }
        return catalog;
    }

    /**
     * 解析DataSource中数据库名
     * @param dataSource
     * @return
     */
    public static Map<String, String> findParaMap(DataSource dataSource) {
        Connection connection = null;
        try {
            connection = dataSource.getConnection();
            DatabaseMetaData metaData = connection.getMetaData();
            String url = metaData.getURL();
            return findParaMapByUrl(url);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }finally {
            try {
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 解析参数Map
     * @param jdbcUrl
     * @return
     */
    public static Map<String, String> findParaMapByUrl(String jdbcUrl) {
        Map<String, String> map = HttpUtil.decodeParamMap(jdbcUrl, Charset.defaultCharset());
        return map;
    }

    /**
     * 获取参数 currentSchema
     * @param dataSource
     * @return
     */
    public static String findSchemaName(DataSource dataSource) {
        Map<String, String> paraMap = findParaMap(dataSource);
        return paraMap.get("currentSchema");
    }

    /**
     * 获取参数 currentSchema
     * @param jdbcUrl
     * @return
     */
    public static String findSchemaName(String jdbcUrl) {
        Map<String, String> paraMap = findParaMapByUrl(jdbcUrl);
        return paraMap.get("currentSchema");
    }
}
